home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / ui_gameinfo.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  16.3 KB  |  801 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. //
  4. // gameinfo.c
  5. //
  6.  
  7. #include "ui_local.h"
  8.  
  9.  
  10. //
  11. // arena and bot info
  12. //
  13.  
  14. #define POOLSIZE    128 * 1024
  15.  
  16. int                ui_numBots;
  17. static char        *ui_botInfos[MAX_BOTS];
  18.  
  19. static int        ui_numArenas;
  20. static char        *ui_arenaInfos[MAX_ARENAS];
  21.  
  22. static int        ui_numSinglePlayerArenas;
  23. static int        ui_numSpecialSinglePlayerArenas;
  24.  
  25. static char        memoryPool[POOLSIZE];
  26. static int        allocPoint, outOfMemory;
  27.  
  28.  
  29. /*
  30. ===============
  31. UI_Alloc
  32. ===============
  33. */
  34. void *UI_Alloc( int size ) {
  35.     char    *p;
  36.  
  37.     if ( allocPoint + size > POOLSIZE ) {
  38.         outOfMemory = qtrue;
  39.         return NULL;
  40.     }
  41.  
  42.     p = &memoryPool[allocPoint];
  43.  
  44.     allocPoint += ( size + 31 ) & ~31;
  45.  
  46.     return p;
  47. }
  48.  
  49. /*
  50. ===============
  51. UI_InitMemory
  52. ===============
  53. */
  54. void UI_InitMemory( void ) {
  55.     allocPoint = 0;
  56.     outOfMemory = qfalse;
  57. }
  58.  
  59. /*
  60. ===============
  61. UI_ParseInfos
  62. ===============
  63. */
  64. int UI_ParseInfos( char *buf, int max, char *infos[] ) {
  65.     char    *token;
  66.     int        count;
  67.     char    key[MAX_TOKEN_CHARS];
  68.     char    info[MAX_INFO_STRING];
  69.  
  70.     count = 0;
  71.  
  72.     while ( 1 ) {
  73.         token = COM_Parse( &buf );
  74.         if ( !token[0] ) {
  75.             break;
  76.         }
  77.         if ( strcmp( token, "{" ) ) {
  78.             Com_Printf( "Missing { in info file\n" );
  79.             break;
  80.         }
  81.  
  82.         if ( count == max ) {
  83.             Com_Printf( "Max infos exceeded\n" );
  84.             break;
  85.         }
  86.  
  87.         info[0] = '\0';
  88.         while ( 1 ) {
  89.             token = COM_ParseExt( &buf, qtrue );
  90.             if ( !token[0] ) {
  91.                 Com_Printf( "Unexpected end of info file\n" );
  92.                 break;
  93.             }
  94.             if ( !strcmp( token, "}" ) ) {
  95.                 break;
  96.             }
  97.             Q_strncpyz( key, token, sizeof( key ) );
  98.  
  99.             token = COM_ParseExt( &buf, qfalse );
  100.             if ( !token[0] ) {
  101.                 strcpy( token, "<NULL>" );
  102.             }
  103.             Info_SetValueForKey( info, key, token );
  104.         }
  105.         //NOTE: extra space for arena number
  106.         infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
  107.         if (infos[count]) {
  108.             strcpy(infos[count], info);
  109.             count++;
  110.         }
  111.     }
  112.     return count;
  113. }
  114.  
  115. /*
  116. ===============
  117. UI_LoadArenasFromFile
  118. ===============
  119. */
  120. static void UI_LoadArenasFromFile( char *filename ) {
  121.     int                len;
  122.     fileHandle_t    f;
  123.     char            buf[MAX_ARENAS_TEXT];
  124.  
  125.     len = trap_FS_FOpenFile( filename, &f, FS_READ );
  126.     if ( !f ) {
  127.         trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
  128.         return;
  129.     }
  130.     if ( len >= MAX_ARENAS_TEXT ) {
  131.         trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
  132.         trap_FS_FCloseFile( f );
  133.         return;
  134.     }
  135.  
  136.     trap_FS_Read( buf, len, f );
  137.     buf[len] = 0;
  138.     trap_FS_FCloseFile( f );
  139.  
  140.     ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
  141. }
  142.  
  143. /*
  144. ===============
  145. UI_LoadArenas
  146. ===============
  147. */
  148. static void UI_LoadArenas( void ) {
  149.     int            numdirs;
  150.     vmCvar_t    arenasFile;
  151.     char        filename[128];
  152.     char        dirlist[1024];
  153.     char*        dirptr;
  154.     int            i, n;
  155.     int            dirlen;
  156.     char        *type;
  157.     char        *tag;
  158.     int            singlePlayerNum, specialNum, otherNum;
  159.  
  160.     ui_numArenas = 0;
  161.  
  162.     trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
  163.     if( *arenasFile.string ) {
  164.         UI_LoadArenasFromFile(arenasFile.string);
  165.     }
  166.     else {
  167.         UI_LoadArenasFromFile("scripts/arenas.txt");
  168.     }
  169.  
  170.     // get all arenas from .arena files
  171.     numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
  172.     dirptr  = dirlist;
  173.     for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
  174.         dirlen = strlen(dirptr);
  175.         strcpy(filename, "scripts/");
  176.         strcat(filename, dirptr);
  177.         UI_LoadArenasFromFile(filename);
  178.     }
  179.     trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
  180.     if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
  181.  
  182.     // set initial numbers
  183.     for( n = 0; n < ui_numArenas; n++ ) {
  184.         Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", n ) );
  185.     }
  186.  
  187.     // go through and count single players levels
  188.     ui_numSinglePlayerArenas = 0;
  189.     ui_numSpecialSinglePlayerArenas = 0;
  190.     for( n = 0; n < ui_numArenas; n++ ) {
  191.         // determine type
  192.         type = Info_ValueForKey( ui_arenaInfos[n], "type" );
  193.  
  194.         // if no type specified, it will be treated as "ffa"
  195.         if( !*type ) {
  196.             continue;
  197.         }
  198.  
  199.         if( strstr( type, "single" ) ) {
  200.             // check for special single player arenas (training, final)
  201.             tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
  202.             if( *tag ) {
  203.                 ui_numSpecialSinglePlayerArenas++;
  204.                 continue;
  205.             }
  206.  
  207.             ui_numSinglePlayerArenas++;
  208.         }
  209.     }
  210.  
  211.     n = ui_numSinglePlayerArenas % ARENAS_PER_TIER;
  212.     if( n != 0 ) {
  213.         ui_numSinglePlayerArenas -= n;
  214.         trap_Print( va( "%i arenas ignored to make count divisible by %i\n", n, ARENAS_PER_TIER ) );
  215.     }
  216.  
  217.     // go through once more and assign number to the levels
  218.     singlePlayerNum = 0;
  219.     specialNum = singlePlayerNum + ui_numSinglePlayerArenas;
  220.     otherNum = specialNum + ui_numSpecialSinglePlayerArenas;
  221.     for( n = 0; n < ui_numArenas; n++ ) {
  222.         // determine type
  223.         type = Info_ValueForKey( ui_arenaInfos[n], "type" );
  224.  
  225.         // if no type specified, it will be treated as "ffa"
  226.         if( *type ) {
  227.             if( strstr( type, "single" ) ) {
  228.                 // check for special single player arenas (training, final)
  229.                 tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
  230.                 if( *tag ) {
  231.                     Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", specialNum++ ) );
  232.                     continue;
  233.                 }
  234.  
  235.                 Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", singlePlayerNum++ ) );
  236.                 continue;
  237.             }
  238.         }
  239.  
  240.         Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", otherNum++ ) );
  241.     }
  242. }
  243.  
  244. /*
  245. ===============
  246. UI_GetArenaInfoByNumber
  247. ===============
  248. */
  249. const char *UI_GetArenaInfoByNumber( int num ) {
  250.     int        n;
  251.     char    *value;
  252.  
  253.     if( num < 0 || num >= ui_numArenas ) {
  254.         trap_Print( va( S_COLOR_RED "Invalid arena number: %i\n", num ) );
  255.         return NULL;
  256.     }
  257.  
  258.     for( n = 0; n < ui_numArenas; n++ ) {
  259.         value = Info_ValueForKey( ui_arenaInfos[n], "num" );
  260.         if( *value && atoi(value) == num ) {
  261.             return ui_arenaInfos[n];
  262.         }
  263.     }
  264.  
  265.     return NULL;
  266. }
  267.  
  268.  
  269. /*
  270. ===============
  271. UI_GetArenaInfoByNumber
  272. ===============
  273. */
  274. const char *UI_GetArenaInfoByMap( const char *map ) {
  275.     int            n;
  276.  
  277.     for( n = 0; n < ui_numArenas; n++ ) {
  278.         if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "map" ), map ) == 0 ) {
  279.             return ui_arenaInfos[n];
  280.         }
  281.     }
  282.  
  283.     return NULL;
  284. }
  285.  
  286.  
  287. /*
  288. ===============
  289. UI_GetSpecialArenaInfo
  290. ===============
  291. */
  292. const char *UI_GetSpecialArenaInfo( const char *tag ) {
  293.     int            n;
  294.  
  295.     for( n = 0; n < ui_numArenas; n++ ) {
  296.         if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "special" ), tag ) == 0 ) {
  297.             return ui_arenaInfos[n];
  298.         }
  299.     }
  300.  
  301.     return NULL;
  302. }
  303.  
  304. /*
  305. ===============
  306. UI_LoadBotsFromFile
  307. ===============
  308. */
  309. static void UI_LoadBotsFromFile( char *filename ) {
  310.     int                len;
  311.     fileHandle_t    f;
  312.     char            buf[MAX_BOTS_TEXT];
  313.  
  314.     len = trap_FS_FOpenFile( filename, &f, FS_READ );
  315.     if ( !f ) {
  316.         trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
  317.         return;
  318.     }
  319.     if ( len >= MAX_BOTS_TEXT ) {
  320.         trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
  321.         trap_FS_FCloseFile( f );
  322.         return;
  323.     }
  324.  
  325.     trap_FS_Read( buf, len, f );
  326.     buf[len] = 0;
  327.     trap_FS_FCloseFile( f );
  328.  
  329.     ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
  330.     if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all bots\n");
  331. }
  332.  
  333. /*
  334. ===============
  335. UI_LoadBots
  336. ===============
  337. */
  338. static void UI_LoadBots( void ) {
  339.     vmCvar_t    botsFile;
  340.     int            numdirs;
  341.     char        filename[128];
  342.     char        dirlist[1024];
  343.     char*        dirptr;
  344.     int            i;
  345.     int            dirlen;
  346.  
  347.     ui_numBots = 0;
  348.  
  349.     trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
  350.     if( *botsFile.string ) {
  351.         UI_LoadBotsFromFile(botsFile.string);
  352.     }
  353.     else {
  354.         UI_LoadBotsFromFile("scripts/bots.txt");
  355.     }
  356.  
  357.     // get all bots from .bot files
  358.     numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
  359.     dirptr  = dirlist;
  360.     for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
  361.         dirlen = strlen(dirptr);
  362.         strcpy(filename, "scripts/");
  363.         strcat(filename, dirptr);
  364.         UI_LoadBotsFromFile(filename);
  365.     }
  366.     trap_Print( va( "%i bots parsed\n", ui_numBots ) );
  367. }
  368.  
  369.  
  370. /*
  371. ===============
  372. UI_GetBotInfoByNumber
  373. ===============
  374. */
  375. char *UI_GetBotInfoByNumber( int num ) {
  376.     if( num < 0 || num >= ui_numBots ) {
  377.         trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
  378.         return NULL;
  379.     }
  380.     return ui_botInfos[num];
  381. }
  382.  
  383.  
  384. /*
  385. ===============
  386. UI_GetBotInfoByName
  387. ===============
  388. */
  389. char *UI_GetBotInfoByName( const char *name ) {
  390.     int        n;
  391.     char    *value;
  392.  
  393.     for ( n = 0; n < ui_numBots ; n++ ) {
  394.         value = Info_ValueForKey( ui_botInfos[n], "name" );
  395.         if ( !Q_stricmp( value, name ) ) {
  396.             return ui_botInfos[n];
  397.         }
  398.     }
  399.  
  400.     return NULL;
  401. }
  402.  
  403.  
  404. //
  405. // single player game info
  406. //
  407.  
  408. /*
  409. ===============
  410. UI_GetBestScore
  411.  
  412. Returns the player's best finish on a given level, 0 if the have not played the level
  413. ===============
  414. */
  415. void UI_GetBestScore( int level, int *score, int *skill ) {
  416.     int        n;
  417.     int        skillScore;
  418.     int        bestScore;
  419.     int        bestScoreSkill;
  420.     char    arenaKey[16];
  421.     char    scores[MAX_INFO_VALUE];
  422.  
  423.     if( !score || !skill ) {
  424.         return;
  425.     }
  426.  
  427.     if( level < 0 || level > ui_numArenas ) {
  428.         return;
  429.     }
  430.  
  431.     bestScore = 0;
  432.     bestScoreSkill = 0;
  433.  
  434.     for( n = 1; n <= 5; n++ ) {
  435.         trap_Cvar_VariableStringBuffer( va( "g_spScores%i", n ), scores, MAX_INFO_VALUE );
  436.  
  437.         Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
  438.         skillScore = atoi( Info_ValueForKey( scores, arenaKey ) );
  439.  
  440.         if( skillScore < 1 || skillScore > 8 ) {
  441.             continue;
  442.         }
  443.  
  444.         if( !bestScore || skillScore <= bestScore ) {
  445.             bestScore = skillScore;
  446.             bestScoreSkill = n;
  447.         }
  448.     }
  449.  
  450.     *score = bestScore;
  451.     *skill = bestScoreSkill;
  452. }
  453.  
  454.  
  455. /*
  456. ===============
  457. UI_SetBestScore
  458.  
  459. Set the player's best finish for a level
  460. ===============
  461. */
  462. void UI_SetBestScore( int level, int score ) {
  463.     int        skill;
  464.     int        oldScore;
  465.     char    arenaKey[16];
  466.     char    scores[MAX_INFO_VALUE];
  467.  
  468.     // validate score
  469.     if( score < 1 || score > 8 ) {
  470.         return;
  471.     }
  472.  
  473.     // validate skill
  474.     skill = (int)trap_Cvar_VariableValue( "g_spSkill" );
  475.     if( skill < 1 || skill > 5 ) {
  476.         return;
  477.     }
  478.  
  479.     // get scores
  480.     trap_Cvar_VariableStringBuffer( va( "g_spScores%i", skill ), scores, MAX_INFO_VALUE );
  481.  
  482.     // see if this is better
  483.     Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
  484.     oldScore = atoi( Info_ValueForKey( scores, arenaKey ) );
  485.     if( oldScore && oldScore <= score ) {
  486.         return;
  487.     }
  488.  
  489.     // update scores
  490.     Info_SetValueForKey( scores, arenaKey, va( "%i", score ) );
  491.     trap_Cvar_Set( va( "g_spScores%i", skill ), scores );
  492. }
  493.  
  494.  
  495. /*
  496. ===============
  497. UI_LogAwardData
  498. ===============
  499. */
  500. void UI_LogAwardData( int award, int data ) {
  501.     char    key[16];
  502.     char    awardData[MAX_INFO_VALUE];
  503.     int        oldValue;
  504.  
  505.     if( data == 0 ) {
  506.         return;
  507.     }
  508.  
  509.     if( award > AWARD_PERFECT ) {
  510.         trap_Print( va( S_COLOR_RED "Bad award %i in UI_LogAwardData\n", award ) );
  511.         return;
  512.     }
  513.  
  514.     trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
  515.  
  516.     Com_sprintf( key, sizeof(key), "a%i", award );
  517.     oldValue = atoi( Info_ValueForKey( awardData, key ) );
  518.  
  519.     Info_SetValueForKey( awardData, key, va( "%i", oldValue + data ) );
  520.     trap_Cvar_Set( "g_spAwards", awardData );
  521. }
  522.  
  523.  
  524. /*
  525. ===============
  526. UI_GetAwardLevel
  527. ===============
  528. */
  529. int UI_GetAwardLevel( int award ) {
  530.     char    key[16];
  531.     char    awardData[MAX_INFO_VALUE];
  532.  
  533.     trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
  534.  
  535.     Com_sprintf( key, sizeof(key), "a%i", award );
  536.     return atoi( Info_ValueForKey( awardData, key ) );
  537. }
  538.  
  539.  
  540. /*
  541. ===============
  542. UI_TierCompleted
  543. ===============
  544. */
  545. int UI_TierCompleted( int levelWon ) {
  546.     int            level;
  547.     int            n;
  548.     int            tier;
  549.     int            score;
  550.     int            skill;
  551.     const char    *info;
  552.  
  553.     tier = levelWon / ARENAS_PER_TIER;
  554.     level = tier * ARENAS_PER_TIER;
  555.  
  556.     if( tier == UI_GetNumSPTiers() ) {
  557.         info = UI_GetSpecialArenaInfo( "training" );
  558.         if( levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
  559.             return 0;
  560.         }
  561.         info = UI_GetSpecialArenaInfo( "final" );
  562.         if( !info || levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
  563.             return tier + 1;
  564.         }
  565.         return -1;
  566.     }
  567.  
  568.     for( n = 0; n < ARENAS_PER_TIER; n++, level++ ) {
  569.         UI_GetBestScore( level, &score, &skill );
  570.         if ( score != 1 ) {
  571.             return -1;
  572.         }
  573.     }
  574.     return tier + 1;
  575. }
  576.  
  577.  
  578. /*
  579. ===============
  580. UI_ShowTierVideo
  581. ===============
  582. */
  583. qboolean UI_ShowTierVideo( int tier ) {
  584.     char    key[16];
  585.     char    videos[MAX_INFO_VALUE];
  586.  
  587.     if( tier <= 0 ) {
  588.         return qfalse;
  589.     }
  590.  
  591.     trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
  592.  
  593.     Com_sprintf( key, sizeof(key), "tier%i", tier );
  594.     if( atoi( Info_ValueForKey( videos, key ) ) ) {
  595.         return qfalse;
  596.     }
  597.  
  598.     Info_SetValueForKey( videos, key, va( "%i", 1 ) );
  599.     trap_Cvar_Set( "g_spVideos", videos );
  600.  
  601.     return qtrue;
  602. }
  603.  
  604.  
  605. /*
  606. ===============
  607. UI_CanShowTierVideo
  608. ===============
  609. */
  610. qboolean UI_CanShowTierVideo( int tier ) {
  611.     char    key[16];
  612.     char    videos[MAX_INFO_VALUE];
  613.  
  614.     if( !tier ) {
  615.         return qfalse;
  616.     }
  617.  
  618.     if( uis.demoversion && tier != 8 ) {
  619.         return qfalse;
  620.     }
  621.  
  622.     trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
  623.  
  624.     Com_sprintf( key, sizeof(key), "tier%i", tier );
  625.     if( atoi( Info_ValueForKey( videos, key ) ) ) {
  626.         return qtrue;
  627.     }
  628.  
  629.     return qfalse;
  630. }
  631.  
  632.  
  633. /*
  634. ===============
  635. UI_GetCurrentGame
  636.  
  637. Returns the next level the player has not won
  638. ===============
  639. */
  640. int UI_GetCurrentGame( void ) {
  641.     int        level;
  642.     int        rank;
  643.     int        skill;
  644.     const char *info;
  645.  
  646.     info = UI_GetSpecialArenaInfo( "training" );
  647.     if( info ) {
  648.         level = atoi( Info_ValueForKey( info, "num" ) );
  649.         UI_GetBestScore( level, &rank, &skill );
  650.         if ( !rank || rank > 1 ) {
  651.             return level;
  652.         }
  653.     }
  654.  
  655.     for( level = 0; level < ui_numSinglePlayerArenas; level++ ) {
  656.         UI_GetBestScore( level, &rank, &skill );
  657.         if ( !rank || rank > 1 ) {
  658.             return level;
  659.         }
  660.     }
  661.  
  662.     info = UI_GetSpecialArenaInfo( "final" );
  663.     if( !info ) {
  664.         return -1;
  665.     }
  666.     return atoi( Info_ValueForKey( info, "num" ) );
  667. }
  668.  
  669.  
  670. /*
  671. ===============
  672. UI_NewGame
  673.  
  674. Clears the scores and sets the difficutly level
  675. ===============
  676. */
  677. void UI_NewGame( void ) {
  678.     trap_Cvar_Set( "g_spScores1", "" );
  679.     trap_Cvar_Set( "g_spScores2", "" );
  680.     trap_Cvar_Set( "g_spScores3", "" );
  681.     trap_Cvar_Set( "g_spScores4", "" );
  682.     trap_Cvar_Set( "g_spScores5", "" );
  683.     trap_Cvar_Set( "g_spAwards", "" );
  684.     trap_Cvar_Set( "g_spVideos", "" );
  685. }
  686.  
  687.  
  688. /*
  689. ===============
  690. UI_GetNumArenas
  691. ===============
  692. */
  693. int UI_GetNumArenas( void ) {
  694.     return ui_numArenas;
  695. }
  696.  
  697.  
  698. /*
  699. ===============
  700. UI_GetNumSPArenas
  701. ===============
  702. */
  703. int UI_GetNumSPArenas( void ) {
  704.     return ui_numSinglePlayerArenas;
  705. }
  706.  
  707.  
  708. /*
  709. ===============
  710. UI_GetNumSPTiers
  711. ===============
  712. */
  713. int UI_GetNumSPTiers( void ) {
  714.     return ui_numSinglePlayerArenas / ARENAS_PER_TIER;
  715. }
  716.  
  717.  
  718. /*
  719. ===============
  720. UI_GetNumBots
  721. ===============
  722. */
  723. int UI_GetNumBots( void ) {
  724.     return ui_numBots;
  725. }
  726.  
  727.  
  728. /*
  729. ===============
  730. UI_SPUnlock_f
  731. ===============
  732. */
  733. void UI_SPUnlock_f( void ) {
  734.     char    arenaKey[16];
  735.     char    scores[MAX_INFO_VALUE];
  736.     int        level;
  737.     int        tier;
  738.  
  739.     // get scores for skill 1
  740.     trap_Cvar_VariableStringBuffer( "g_spScores1", scores, MAX_INFO_VALUE );
  741.  
  742.     // update scores
  743.     for( level = 0; level < ui_numSinglePlayerArenas + ui_numSpecialSinglePlayerArenas; level++ ) {
  744.         Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
  745.         Info_SetValueForKey( scores, arenaKey, "1" );
  746.     }
  747.     trap_Cvar_Set( "g_spScores1", scores );
  748.  
  749.     // unlock cinematics
  750.     for( tier = 1; tier <= 8; tier++ ) {
  751.         UI_ShowTierVideo( tier );
  752.     }
  753.  
  754.     trap_Print( "All levels unlocked at skill level 1\n" );
  755.  
  756.     UI_SPLevelMenu_ReInit();
  757. }
  758.  
  759.  
  760. /*
  761. ===============
  762. UI_SPUnlockMedals_f
  763. ===============
  764. */
  765. void UI_SPUnlockMedals_f( void ) {
  766.     int        n;
  767.     char    key[16];
  768.     char    awardData[MAX_INFO_VALUE];
  769.  
  770.     trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, MAX_INFO_VALUE );
  771.  
  772.     for( n = 0; n < 6; n++ ) {
  773.         Com_sprintf( key, sizeof(key), "a%i", n );
  774.         Info_SetValueForKey( awardData, key, "100" );
  775.     }
  776.  
  777.     trap_Cvar_Set( "g_spAwards", awardData );
  778.  
  779.     trap_Print( "All levels unlocked at 100\n" );
  780. }
  781.  
  782.  
  783. /*
  784. ===============
  785. UI_InitGameinfo
  786. ===============
  787. */
  788. void UI_InitGameinfo( void ) {
  789.  
  790.     UI_InitMemory();
  791.     UI_LoadArenas();
  792.     UI_LoadBots();
  793.  
  794.     if( (trap_Cvar_VariableValue( "fs_restrict" )) || (ui_numSpecialSinglePlayerArenas == 0 && ui_numSinglePlayerArenas == 4) ) {
  795.         uis.demoversion = qtrue;
  796.     }
  797.     else {
  798.         uis.demoversion = qfalse;
  799.     }
  800. }
  801.